package jp.fsoriented.toishi.data;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.os.Parcel;
import android.os.Parcelable;

public class Verse implements Parcelable {

	/** み言葉の位置(not null) */
	public final VersePtr position;
	/** み言葉の範囲(not null) */
	public final VersePtr toLocation;
	/** み言葉を範囲とするかどうか */
	public boolean isRange;
	/** み言葉のヒント */
	public String hint;
	/** み言葉 */
	public String content;
	/** 登録した日時 */
	public final Date addedDate;
	/** 暗唱履歴：成功回数 */
	public int okCount;
	/** 暗唱履歴(not null) */
	public final List<Result> result;

	/**
	 * コンストラクタ
	 */
	public Verse() {
		position = new VersePtr();
		toLocation = new VersePtr();
		isRange = false;
		hint = null;
		content = null;
		addedDate = new Date();
		okCount = 0;
		result = new ArrayList<Result>();
	}

	public int describeContents() {
		return 0;
	}

	public void writeToParcel(Parcel dest, int flags) {
		dest.writeParcelable(position, 0);
		dest.writeParcelable(toLocation, 0);
		dest.writeInt((isRange) ? (1) : (0));
		dest.writeString(hint);
		dest.writeString(content);
		dest.writeSerializable(addedDate);
		dest.writeInt(okCount);
		dest.writeTypedList(result);
	}

	public static final Parcelable.Creator<Verse> CREATOR = new Parcelable.Creator<Verse>() {
		public Verse createFromParcel(Parcel in) {
			Verse verse = new Verse();
			verse.position.set((VersePtr) in.readParcelable(VersePtr.class.getClassLoader()));
			verse.toLocation.set((VersePtr) in.readParcelable(VersePtr.class.getClassLoader()));
			verse.isRange = (1 == in.readInt());
			verse.hint = in.readString();
			verse.content = in.readString();
			verse.addedDate.setTime(((Date) in.readSerializable()).getTime());
			verse.okCount = in.readInt();
			in.readTypedList(verse.result, Result.CREATOR);
			return verse;
		}

		public Verse[] newArray(int size) {
			return new Verse[size];
		}
	};

	public JSONObject asJSONObject() throws JSONException {
		JSONObject obj = new JSONObject();
		obj.put("position", position.asJSONObject());
		obj.put("toLocation", toLocation.asJSONObject());
		obj.put("isRange", isRange);
		obj.put("hint", hint);
		obj.put("content", content);
		obj.put("addedDate", addedDate.getTime());
		obj.put("okCount", okCount);
		JSONArray array = new JSONArray();
		for (Result r : result) {
			array.put(r.asJSONObject());
		}
		obj.put("result", array);
		return obj;
	}

	public static Verse fromJsonObject(JSONObject obj) throws JSONException {
		Verse verse = new Verse();
		verse.position.set(VersePtr.fromJsonObject(obj.getJSONObject("position")));
		verse.toLocation.set(VersePtr.fromJsonObject(obj.getJSONObject("toLocation")));
		verse.isRange = obj.getBoolean("isRange");
		verse.hint = obj.getString("hint");
		verse.content = obj.getString("content");
		verse.addedDate.setTime(obj.getLong("addedDate"));
		verse.okCount = obj.getInt("okCount");
		List<Result> array = verse.result;
		JSONArray jarr = obj.getJSONArray("result");
		int count = jarr.length();
		for (int i = 0; i < count; i++) {
			JSONObject o = (JSONObject) jarr.get(i);
			Result r = Result.fromJsonObject(o);
			array.add(r);
		}
		return verse;
	}

	/**
	 * み言葉の箇所をあらわす文字列を返す
	 * 
	 * @param loc
	 * @return
	 */
	public String getLocationName() {
		StringBuilder sb = new StringBuilder();
		sb.append(BibleConstant.getBookName(position.book));
		sb.append(" ");
		sb.append(position.chapter + 1);
		sb.append("章");
		sb.append(position.verse + 1);
		sb.append("節");
		if (isRange) {
			sb.append("～");
			if (toLocation.chapter != position.chapter) {
				sb.append(toLocation.chapter + 1);
				sb.append("章");
			}
			sb.append(toLocation.verse + 1);
			sb.append("節");
		}
		return sb.toString();
	}

	/**
	 * このオブジェクトの情報を正規化する。
	 * １．toLocationが指定されている場合、toLocationが後ろになるようにする
	 * ２．okCountの計算しなおし
	 */
	public void normalize() {
		if (isRange) {
			if (position.chapter > toLocation.chapter) {
				// 交換
				swapChapter(position, toLocation);
				swapVerse(position, toLocation);
			} else if ((position.chapter == toLocation.chapter) && (position.verse > toLocation.verse)) {
				// 交換
				swapVerse(position, toLocation);
			} else if ((position.chapter == toLocation.chapter) && (position.verse == toLocation.verse)) {
				// 範囲ではない
				toLocation.set(0, 0, 0);
				isRange = false;
			}
		}
		calcOkCount();
	}

	private void calcOkCount() {
		int count = 0;
		for (Result r : result) {
			if (r.ok) {
				count++;
			}
		}
		okCount = count;
	}

	private void swapChapter(VersePtr p1, VersePtr p2) {
		int chapter = p2.chapter;
		p2.chapter = p1.chapter;
		p1.chapter = chapter;
	}

	private void swapVerse(VersePtr p1, VersePtr p2) {
		int verse = p2.verse;
		p2.verse = p1.verse;
		p1.verse = verse;
	}
}
